package bjut.zrpc.core.optimization.event;

import bjut.zrpc.core.optimization.utils.ClassUtil;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;

/**
 * @Author: zhuzhiming
 * @Date: 2022/7/2 23:13
 */
public abstract class AbstractApplicationEventMulticaster implements ZRpcEventMulticaster {


    public static  Set<ZRpcEventListener<?>> zRpcEventListeners = new LinkedHashSet<>();

    @Override
    public void addZRpcEventListener(ZRpcEventListener<?> zRpcEventListener) {
        zRpcEventListeners.add(zRpcEventListener);
    }

    @Override
    public void removeZRpcEventListener(ZRpcEventListener<?> zRpcEventListener) {
        zRpcEventListeners.remove(zRpcEventListener);
    }

    public Collection<ZRpcEventListener> getZRpcListeners(ZRpcEvent event) {

        ArrayList<ZRpcEventListener> matchListeners = new ArrayList<>();

        for (ZRpcEventListener<?> listener : this.zRpcEventListeners) {

            if (support(listener, event)) {
                matchListeners.add(listener);
            }
        }
        return matchListeners;
    }

    private boolean support(ZRpcEventListener<?> listener, ZRpcEvent event) {

        Class<? extends ZRpcEventListener> listenerClass = listener.getClass();
        Class<?> targetClass = ClassUtil.isCglibProxyClass(listenerClass) ? listenerClass.getSuperclass() : listenerClass;

        Type genericInterface = targetClass.getGenericInterfaces()[0];
        Type actualTypeArgument = ((ParameterizedType) genericInterface).getActualTypeArguments()[0];

        String className = actualTypeArgument.getTypeName();
        Class<?> eventClass;
        try {
            eventClass = Class.forName(className);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e.getMessage());
        }

        return eventClass.isAssignableFrom(event.getClass());

    }

}
